home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 4
/
QRZ Ham Radio Callsign Database - Volume 4.iso
/
files
/
dsp
/
56ktools
/
dspkgctr.z
/
dspkgctr
/
gcc
/
rtl.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-08
|
20KB
|
835 lines
/* Allocate, read and print RTL for C-Compiler
Copyright (C) 1987, 1988 Free Software Foundation, Inc.
$Id: rtl.c,v 1.8 91/10/23 17:02:56 pete Exp $
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include <ctype.h>
#include <stdio.h>
#include "rtl.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern int xmalloc ();
extern void free ();
/* Obstack used for allocating RTL objects.
Between functions, this is the permanent_obstack.
While parsing and expanding a function, this is maybepermanent_obstack
so we can save it if it is an inline function.
During optimization and output, this is temporary_obstack. */
extern struct obstack *rtl_obstack;
#define MIN(x,y) ((x < y) ? x : y)
extern long ftell();
/* Indexed by rtx code, gives number of operands for an rtx with that code.
Does NOT include rtx header data (code and links).
This array is initialized in init_rtl. */
int rtx_length[NUM_RTX_CODE + 1];
/* Indexed by rtx code, gives the name of that kind of rtx, as a C string. */
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT) NAME ,
char *rtx_name[] = {
#include "rtl.def" /* rtl expressions are documented here */
};
#undef DEF_RTL_EXPR
/* Indexed by machine mode, gives the name of that machine mode.
This name does not include the letters "mode". */
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) NAME,
char *mode_name[] = {
#include "machmode.def"
};
#undef DEF_MACHMODE
/* Indexed by machine mode, gives the length of the mode, in bytes.
GET_MODE_CLASS uses this. */
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) CLASS,
enum mode_class mode_class[] = {
#include "machmode.def"
};
#undef DEF_MACHMODE
/* Indexed by machine mode, gives the length of the mode, in bytes.
GET_MODE_SIZE uses this. */
#if defined( DSP56000 )
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
(SIZE),
#else
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
(SIZE*UNITS_PER_WORD+3)/4,
#endif
int mode_size[] = {
#include "machmode.def"
};
#undef DEF_MACHMODE
/* Indexed by machine mode, gives the length of the mode's subunit.
GET_MODE_UNIT_SIZE uses this. */
#if defined( DSP56000 )
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
(UNIT),
#else
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
(UNIT*UNITS_PER_WORD+3)/4,
#endif
int mode_unit_size[] = {
#include "machmode.def" /* machine modes are documented here */
};
#undef DEF_MACHMODE
/* Indexed by machine mode, gives next wider natural mode
(QI -> HI -> SI -> DI, etc.) Widening multiply instructions
use this. */
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
(enum machine_mode) WIDER,
enum machine_mode mode_wider_mode[] = {
#include "machmode.def" /* machine modes are documented here */
};
#undef DEF_MACHMODE
/* Indexed by rtx code, gives a sequence of operand-types for
rtx's of that code. The sequence is a C string in which
each charcter describes one operand. */
char *rtx_format[] = {
/* "*" undefined.
can cause a warning message
"0" field is unused (or used in a phase-dependent manner)
prints nothing
"i" an integer
prints the integer
"s" a pointer to a string
prints the string
"S" like "s", but optional:
the containing rtx may end before this operand
"e" a pointer to an rtl expression
prints the expression
"E" a pointer to a vector that points to a number of rtl expressions
prints a list of the rtl expressions
"u" a pointer to another insn
prints the uid of the insn. */
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT) FORMAT ,
#include "rtl.def" /* rtl expressions are defined here */
#undef DEF_RTL_EXPR
};
/* Names for kinds of NOTEs and REG_NOTEs. */
char *note_insn_name[] = { "NOTE_INSN_FUNCTION_BEG", "NOTE_INSN_DELETED",
"NOTE_INSN_BLOCK_BEG", "NOTE_INSN_BLOCK_END",
"NOTE_INSN_LOOP_BEG", "NOTE_INSN_LOOP_END",
"NOTE_INSN_FUNCTION_END", "NOTE_INSN_SETJMP",
"NOTE_INSN_LOOP_CONT" };
char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
"REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
"REG_NONNEG", "REG_ASM_LINE", "REG_ASM_FILE" };
/* Allocate an rtx vector of N elements.
Store the length, and initialize all elements to zero. */
rtvec
rtvec_alloc (n)
int n;
{
rtvec rt;
int i;
rt = (rtvec) obstack_alloc (rtl_obstack,
sizeof (struct rtvec_def)
+ (( n - 1) * sizeof (rtunion)));
/* clear out the vector */
PUT_NUM_ELEM(rt, n);
for (i=0; i < n; i++)
rt->elem[i].rtvec = NULL; /* @@ not portable due to rtunion */
return rt;
}
/* Allocate an rtx of code CODE. The CODE is stored in the rtx;
all the rest is initialized to zero. */
rtx
rtx_alloc (code)
RTX_CODE code;
{
rtx rt;
register int nelts = GET_RTX_LENGTH (code);
register int length = sizeof (struct rtx_def)
+ (nelts - 1) * sizeof (rtunion);
rt = (rtx) obstack_alloc (rtl_obstack, length);
#if defined( DSP56000 ) || defined( DSP96000 )
/* guarentee that EVERYTHING is cleared */
bzero( (char*) rt, length );
#else
* (int *) rt = 0;
#endif
PUT_CODE (rt, code);
return rt;
}
/* Create a new copy of an rtx.
Recursively copies the operands of the rtx,
except for those few rtx codes that are sharable. */
rtx
copy_rtx (orig)
register rtx orig;
{
register rtx copy;
register int i, j;
register RTX_CODE code;
register char *format_ptr;
code = GET_CODE (orig);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
return orig;
}
copy = rtx_alloc (code);
PUT_MODE (copy, GET_MODE (orig));
copy->in_struct = orig->in_struct;
copy->volatil = orig->volatil;
copy->unchanging = orig->unchanging;
copy->integrated = orig->integrated;
#if defined( DSP56000 )
/* added fields for DSP enhancements. */
copy->reload_subreg = orig->reload_subreg;
#endif
#if defined( DSP56000 ) || defined( DSP96000 )
copy->reload_generated = orig->reload_generated;
#endif
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
switch (*format_ptr++)
{
case 'e':
XEXP (copy, i) = XEXP (orig, i);
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_rtx (XEXP (orig, i));
break;
case 'E':
XVEC (copy, i) = XVEC (orig, i);
if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
}
break;
default:
XINT (copy, i) = XINT (orig, i);
break;
}
}
return copy;
}
/* Printing rtl for debugging dumps. */
static FILE *outfile;
char spaces[] = " ";
static int sawclose = 0;
/* Print IN_RTX onto OUTFILE. This is the recursive part of printing. */
static void
print_rtx (in_rtx)
register rtx in_rtx;
{
static int indent;
register int i, j;
register char *format_ptr;
if (sawclose)
{
fprintf (outfile, "\n%s",
(spaces + (sizeof spaces - indent * 2)));
sawclose = 0;
}
if (in_rtx == 0)
{
fprintf (outfile, "(nil)");
sawclose = 1;
return;
}
/* print name of expression code */
fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
if (in_rtx->in_struct)
fprintf (outfile, "/s");
if (in_rtx->volatil)
fprintf (outfile, "/v");
if (in_rtx->unchanging)
fprintf (outfile, "/u");
if (in_rtx->integrated)
fprintf (outfile, "/i");
if (GET_MODE (in_rtx) != VOIDmode)
{
/* Print REG_NOTE names for EXPR_LIST and INSN_LIST. */
if (GET_CODE (in_rtx) == EXPR_LIST || GET_CODE (in_rtx) == INSN_LIST)
fprintf (outfile, ":%s", GET_REG_NOTE_NAME (GET_MODE (in_rtx)));
else
fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx)));
}
format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
switch (*format_ptr++)
{
case 'S':
case 's':
if (XSTR (in_rtx, i) == 0)
fprintf (outfile, " \"\"");
else
fprintf (outfile, " (\"%s\")", XSTR (in_rtx, i));
sawclose = 1;
break;
/* 0 indicates a field for internal use that should not be printed. */
case '0':
break;
case 'e':
indent += 2;
if (!sawclose)
fprintf (outfile, " ");
print_rtx (XEXP (in_rtx, i));
indent -= 2;
break;
case 'E':
indent += 2;
if (sawclose)
{
fprintf (outfile, "\n%s",
(spaces + (sizeof spaces - indent * 2)));
sawclose = 0;
}
fprintf (outfile, "[ ");
if (NULL != XVEC (in_rtx, i))
{
indent += 2;
if (XVECLEN (in_rtx, i))
sawclose = 1;
for (j = 0; j < XVECLEN (in_rtx, i); j++)
print_rtx (XVECEXP (in_rtx, i, j));
indent -= 2;
}
if (sawclose)
fprintf (outfile, "\n%s",
(spaces + (sizeof spaces - indent * 2)));
fprintf (outfile, "] ");
sawclose = 1;
indent -= 2;
break;
case 'i':
fprintf (outfile, " %d", XINT (in_rtx, i));
sawclose = 0;
break;
/* Print NOTE_INSN names rather than integer codes. */
case 'n':
if (XINT (in_rtx, i) <= 0)
fprintf (outfile, " %s", GET_NOTE_INSN_NAME (XINT (in_rtx, i)));
else
fprintf (outfile, " %d", XINT (in_rtx, i));
sawclose = 0;
break;
case 'u':
if (XEXP (in_rtx, i) != NULL)
fprintf(outfile, " %d", INSN_UID (XEXP (in_rtx, i)));
else
fprintf(outfile, " 0");
sawclose = 0;
break;
default:
fprintf (stderr,
"switch format wrong in rtl.print_rtx(). format was: %c.\n",
format_ptr[-1]);
abort ();
}
fprintf (outfile, ")");
sawclose = 1;
}
/* Call this function from the debugger to see what X looks like. */
void
debug_rtx (x)
rtx x;
{
outfile = stderr;
print_rtx (x);
fprintf (stderr, "\n");
}
/* External entry point for printing a chain of insns
starting with RTX_FIRST onto file OUTF.
A blank line separates insns.
If RTX_FIRST is not an insn, then it alone is printed, with no newline. */
void
print_rtl (outf, rtx_first)
FILE *outf;
rtx rtx_first;
{
register rtx tmp_rtx;
outfile = outf;
sawclose = 0;
switch (GET_CODE (rtx_first))
{
case INSN:
case JUMP_INSN:
case CALL_INSN:
case NOTE:
case CODE_LABEL:
case BARRIER:
for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
{
print_rtx (tmp_rtx);
fprintf (outfile, "\n");
}
break;
default:
print_rtx (rtx_first);
}
}
/* Subroutines of read_rtx. */
/* Dump code after printing a message. Used when read_rtx finds
invalid data. */
static void
dump_and_abort (expected_c, actual_c, infile)
int expected_c, actual_c;
FILE *infile;
{
int c, i;
if (expected_c >= 0)
fprintf (stderr,
"Expected character %c. Found character %c.",
expected_c, actual_c);
fprintf (stderr, " At file position: %ld\n", ftell (infile));
fprintf (stderr, "Following characters are:\n\t");
for (i = 0; i < 200; i++)
{
c = getc (infile);
if (EOF == c) break;
putc (c, stderr);
}
fprintf (stderr, "Aborting.\n");
abort ();
}
/* Read chars from INFILE until a non-whitespace char
and return that. Comments, both Lisp style and C style,
are treated as whitespace.
Tools such as genflags use this function. */
int
read_skip_spaces (infile)
FILE *infile;
{
register int c;
while (c = getc (infile))
{
if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
;
else if (c == ';')
{
while ((c = getc (infile)) && c != '\n') ;
}
else if (c == '/')
{
register int prevc;
c = getc (infile);
if (c != '*')
dump_and_abort ('*', c, infile);
prevc = 0;
while (c = getc (infile))
{
if (prevc == '*' && c == '/')
break;
prevc = c;
}
}
else break;
}
return c;
}
/* Read an rtx code name into the buffer STR[].
It is terminated by any of the punctuation chars of rtx printed syntax. */
static void
read_name (str, infile)
char *str;
FILE *infile;
{
register char *p;
register int c;
c = read_skip_spaces(infile);
p = str;
while (1)
{
if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
break;
if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/'
|| c == '(' || c == '[')
{
ungetc (c, infile);
break;
}
*p++ = c;
c = getc (infile);
}
if (p == str)
{
fprintf (stderr, "missing name or number");
dump_and_abort (-1, -1, infile);
}
*p = 0;
}
/* Read an rtx in printed representation from INFILE
and return an actual rtx in core constructed accordingly.
read_rtx is not used in the compiler proper, but rather in
the utilities gen*.c that construct C code from machine descriptions. */
rtx
read_rtx (infile)
FILE *infile;
{
register int i, j, list_counter;
RTX_CODE tmp_code;
register char *format_ptr;
/* tmp_char is a buffer used for reading decimal integers
and names of rtx types and machine modes.
Therefore, 256 must be enough. */
char tmp_char[256];
rtx return_rtx;
register int c;
int tmp_int;
/* Linked list structure for making RTXs: */
struct rtx_list
{
struct rtx_list *next;
rtx value; /* Value of this node... */
};
c = read_skip_spaces (infile); /* Should be open paren. */
if (c != '(')
dump_and_abort ('(', c, infile);
read_name (tmp_char, infile);
tmp_code = UNKNOWN;
for (i=0; i < NUM_RTX_CODE; i++) /* @@ might speed this search up */
{
if (!(strcmp (tmp_char, GET_RTX_NAME (i))))
{
tmp_code = (RTX_CODE) i; /* get value for name */
break;
}
}
if (tmp_code == UNKNOWN)
{
fprintf (stderr,
"Unknown rtx read in rtl.read_rtx(). Code name was %s .",
tmp_char);
}
/* (NIL) stands for an expression that isn't there. */
if (tmp_code == NIL)
{
/* Discard the closeparen. */
while ((c = getc (infile)) && c != ')');
return 0;
}
return_rtx = rtx_alloc (tmp_code); /* if we end up with an insn expression
then we free this space below. */
format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx));
/* If what follows is `: mode ', read it and
store the mode in the rtx. */
i = read_skip_spaces (infile);
if (i == ':')
{
register int k;
read_name (tmp_char, infile);
for (k = 0; k < NUM_MACHINE_MODES; k++)
if (!strcmp (GET_MODE_NAME (k), tmp_char))
break;
PUT_MODE (return_rtx, (enum machine_mode) k );
}
else
ungetc (i, infile);
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++)
switch (*format_ptr++)
{
/* 0 means a field for internal use only.
Don't expect it to be present in the input. */
case '0':
break;
case 'e':
case 'u':
XEXP (return_rtx, i) = read_rtx (infile);
break;
case 'E':
{
register struct rtx_list *next_rtx, *rtx_list_link;
struct rtx_list *list_rtx;
c = read_skip_spaces (infile);
if (c != '[')
dump_and_abort ('[', c, infile);
/* add expressions to a list, while keeping a count */
next_rtx = NULL;
list_counter = 0;
while ((c = read_skip_spaces (infile)) && c != ']')
{
ungetc (c, infile);
list_counter++;
rtx_list_link = (struct rtx_list *)
alloca (sizeof (struct rtx_list));
rtx_list_link->value = read_rtx (infile);
if (next_rtx == 0)
list_rtx = rtx_list_link;
else
next_rtx->next = rtx_list_link;
next_rtx = rtx_list_link;
rtx_list_link->next = 0;
}
/* get vector length and allocate it */
XVEC (return_rtx, i) = (list_counter
? rtvec_alloc (list_counter)
: NULL);
if (list_counter > 0)
{
next_rtx = list_rtx;
for (j = 0; j < list_counter; j++,
next_rtx = next_rtx->next)
XVECEXP (return_rtx, i, j) = next_rtx->value;
}
/* close bracket gotten */
}
break;
case 'S':
/* 'S' is an optional string: if a closeparen follows,
just store NULL for this element. */
c = read_skip_spaces (infile);
ungetc (c, infile);
if (c == ')')
{
XSTR (return_rtx, i) = 0;
break;
}
case 's':
{
int saw_paren = 0;
register char *stringbuf;
int stringbufsize;
c = read_skip_spaces (infile);
if (c == '(')
{
saw_paren = 1;
c = read_skip_spaces (infile);
}
if (c != '"')
dump_and_abort ('"', c, infile);
j = 0;
stringbufsize = 10;
stringbuf = (char *) xmalloc (stringbufsize + 1);
while (1)
{
if (j >= stringbufsize - 4)
{
stringbufsize *= 2;
stringbuf = (char *) xrealloc (stringbuf, stringbufsize + 1);
}
stringbuf[j] = getc (infile); /* Read the string */
if (stringbuf[j] == '\\')
{
stringbuf[j] = getc (infile); /* Read the string */
/* \; makes stuff for a C string constant containing
newline and tab. */
if (stringbuf[j] == ';')
{
strcpy (&stringbuf[j], "\\n\\t");
j += 3;
}
}
else if (stringbuf[j] == '"')
break;
j++;
}
stringbuf[j] = 0; /* NUL terminate the string */
stringbuf = (char *) xrealloc (stringbuf, j + 1);
if (saw_paren)
{
c = read_skip_spaces (infile);
if (c != ')')
dump_and_abort (')', c, infile);
}
XSTR (return_rtx, i) = stringbuf;
}
break;
case 'i':
case 'n':
read_name (tmp_char, infile);
tmp_int = atoi (tmp_char);
XINT (return_rtx, i) = tmp_int;
break;
default:
fprintf (stderr,
"switch format wrong in rtl.read_rtx(). format was: %c.\n",
format_ptr[-1]);
fprintf (stderr, "\tfile position: %ld\n", ftell (infile));
abort ();
}
c = read_skip_spaces (infile);
if (c != ')')
dump_and_abort (')', c, infile);
return return_rtx;
}
/* This is called once per compilation, before any rtx's are constructed.
It initializes the vector `rtx_length'. */
void
init_rtl ()
{
int i;
for (i = 0; i < NUM_RTX_CODE; i++)
rtx_length[i] = strlen (rtx_format[i]);
/* Make CONST_DOUBLE bigger, if real values are bigger than
it normally expects to have room for.
Note that REAL_VALUE_TYPE is not defined by default,
since tree.h is not included. But the default dfn as `double'
would do no harm. */
#ifdef REAL_VALUE_TYPE
i = sizeof (REAL_VALUE_TYPE) / sizeof (rtunion) + 2;
if (rtx_length[(int) CONST_DOUBLE] < i)
{
char *s = (char *) malloc (i + 1);
rtx_length[(int) CONST_DOUBLE] = i;
rtx_format[(int) CONST_DOUBLE] = s;
*s++ = 'e';
*s++ = '0';
/* Set the GET_RTX_FORMAT of CONST_DOUBLE to a string
of as many `i's as we now have elements. */
for (i = 0; i < rtx_length[(int) CONST_DOUBLE]; i++)
*s++ = 'i';
*s++ = 0;
}
#endif
}